package br.com.fiap.atividade5.dao;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import br.com.fiap.atividade5.entity.Entity;

public abstract class GenericDAO<T extends Entity> {
	private static final String URL = "jdbc:mysql://localhost:3306/registro_pedidos";
	private Connection cn;

	protected final boolean abreConexao() throws Exception {
		try {
			Class.forName("com.mysql.jdbc.Driver");
			cn = DriverManager.getConnection(URL, "root", "123123");
			return true;
		} catch (Exception ex) {
			throw ex;
		}
	}
	
	protected final void fechaConexao() throws Exception {
		cn.close();
	}
	
	public final Boolean insert(T entity) throws Exception {
		
		int output = 0;
		
		try {
			abreConexao();
			
			PreparedStatement st = doInsertStatement(entity);
			
			output = st.executeUpdate();
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			fechaConexao();
		}
		
		return output > 0;
	}

	public final Boolean update(T entity) throws Exception {
		
		int output = 0;
		
		try {
			abreConexao();
			
			PreparedStatement st = doUpdateStatement(entity);
			
			output = st.executeUpdate();
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			fechaConexao();
		}
		
		return output > 0;
	}

	public final Boolean delete(T entity) throws Exception {
		
		int output = 0;
		
		try {
			abreConexao();
			
			PreparedStatement rs = doDeleteStatement(entity);
			
			output = rs.executeUpdate();
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			fechaConexao();
		}
		
		return output > 0; 
	}
	
	public final T searchById(Long id) throws Exception {
		
		T entity = null;
		
		try {
			abreConexao();
			
			PreparedStatement st = doGetByIdyStatement(id);
			
			ResultSet rs = st.executeQuery();
			
			if (!rs.next()) {
				return null;
			}
			
			entity = createEntityByResultSet(rs);
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			fechaConexao();
		}
		
		return entity;
	}
	
	public final void saveOrUpdate(T entity) throws SQLException {
		
		try {
			
			if (entity.getCodigo() == null) {
				this.insert(entity);
			} else {
				this.update(entity);
			}
			
		} catch (Exception e) {
			e.printStackTrace();
			throw new SQLException("Erro ao salvar registro na base de dados.");
		}
		
	}
	
	
	protected Connection getConnection() {
		return cn;
	}
	
	protected abstract PreparedStatement doGetByIdyStatement(Long id) throws SQLException;
	protected abstract PreparedStatement doInsertStatement(T entity) throws SQLException;
	protected abstract PreparedStatement doUpdateStatement(T entity) throws SQLException;
	protected abstract PreparedStatement doDeleteStatement(T entity) throws SQLException;
	protected abstract T createEntityByResultSet(ResultSet rs) throws SQLException;
	
}
